package test.pt.mauromad.guias;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axis2.databinding.ADBBean;

import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.AddressStructurePT;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.EnvioDocumentoTransporteRequestElem;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.Line;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.MovementStatus;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.MovementType;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.PostalCodePT;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFPTPortugueseVatNumber;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFPTtextTypeMandatoryMax100Car;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFPTtextTypeMandatoryMax200Car;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFPTtextTypeMandatoryMax20Car;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFPTtextTypeMandatoryMax32Car;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFPTtextTypeMandatoryMax50Car;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFPTtextTypeMandatoryMax60Car;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFdateTimeType;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFdateType;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFdecimalType;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.SAFmonetaryType;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.StockMovement;
import pt.gov.portaldasfinancas.servicos.sgdtws.documentostransporte.StockMovementChoice_type0;
import pt.mauromad.guias.utils.DateUtils;
import pt.mauromad.guias.ws.financas.documentosTransporte.DocumentosTransporteStub;

public class Main {
	public static void main(String[] args) throws Exception {
		DocumentosTransporteStub stub = new DocumentosTransporteStub(
				"https://servicos.portaldasfinancas.gov.pt:701/sgdtws/documentosTransporte");

		stub.envioDocumentoTransporte(getDocument());

		System.out.println(writeADBBean(getDocument()));

	}

	public static EnvioDocumentoTransporteRequestElem getDocument() {
		EnvioDocumentoTransporteRequestElem ed = new EnvioDocumentoTransporteRequestElem();
		StockMovement sm = new StockMovement();
		ed.setEnvioDocumentoTransporteRequestElem(sm);

		sm.setTaxRegistrationNumber(getNIF("220652341"));
		sm.setCompanyName(get100("DIJOSER"));
		sm.setCompanyAddress(getAddress("Rua da Paz", "Peniche", "2359-123"));
		sm.setDocumentNumber(getDocumentNumber());
		// sm.setATDocCodeID(param);
		sm.setMovementStatus(getStatus());

		sm.setMovementDate(getDateTime(new Date()));

		sm.setMovementType(getMovementType());
		sm.setStockMovementChoice_type0(getTaxId("222131231"));

		sm.setCustomerName(get100("Oh Amaral"));
		sm.setCustomerAddress(getAddress("Rua das Bombeiros", "Leiria",
				"2800-234"));

		sm.setAddressTo(getAddress("Rua destino", "Porto", "2000-001"));

		sm.setAddressFrom(getAddress("Rua origem", "Caldas da Rainha",
				"3000-004"));

		sm.setMovementEndTime(getTime("2013-10-23 22:34"));
		sm.setMovementStartTime(getTime("2013-10-23 22:34"));

		sm.setVehicleID(get32("MD-34-25"));

		sm.setLine(getLines());

		return ed;
	}

	private static Line[] getLines() {

		Line[] lines = new Line[10];

		for (int i = 0; i < lines.length; ++i) {
			Line l = lines[i] = new Line();

			// TODO ???
			l.setOrderReferences(null);
			l.setProductDescription(get200(String.format("Produto n.%s", i)));
			l.setQuantity(getQty(i));
			l.setUnitOfMeasure(get20("Metros"));
			l.setUnitPrice(getPrice(i));
		}

		return lines;
	}

	private static SAFmonetaryType getPrice(int val) {
		SAFmonetaryType price = new SAFmonetaryType();
		price.setSAFmonetaryType(new BigDecimal(val));
		return price;
	}

	private static SAFdecimalType getQty(float val) {
		SAFdecimalType value = new SAFdecimalType();
		value.setSAFdecimalType(new BigDecimal(val));
		return value;
	}

	private static SAFdateTimeType getTime(String date) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");

		try {
			return getTime(df.parse(date));
		} catch (ParseException e) {
			throw new RuntimeException(e);
		}
	}

	private static SAFdateTimeType getTime(Date date) {
		SAFdateTimeType time = new SAFdateTimeType();
		time.setSAFdateTimeType(Calendar.getInstance());
		time.getSAFdateTimeType().setTime(date);
		return time;
	}

	private static SAFdateType getDateTime(Date date) {
		SAFdateType dat = new SAFdateType();
		dat.setSAFdateType(date);
		return dat;
	}

	private static StockMovementChoice_type0 getTaxId(String taxNumber) {
		StockMovementChoice_type0 taxId = new StockMovementChoice_type0();

		taxId.setCustomerTaxID(get20(taxNumber));
		return taxId;
	}

	private static MovementType getMovementType() {
		return MovementType.GT;
	}

	private static MovementStatus getStatus() {
		return MovementStatus.N;
	}

	private static SAFPTtextTypeMandatoryMax60Car getDocumentNumber() {
		return get60("2013 A/1");
	}

	private static AddressStructurePT getAddress(String morada, String cidade,
			String codPostal) {
		AddressStructurePT address = new AddressStructurePT();
		address.setAddressdetail(get100(morada));
		address.setCity(get50(cidade));

		PostalCodePT postalCode = new PostalCodePT();
		address.setPostalCode(postalCode);
		postalCode.setPostalCodePT(codPostal);

		address.setCountry("PT");

		return address;
	}

	private static SAFPTPortugueseVatNumber getNIF(String Nif) {
		SAFPTPortugueseVatNumber nif = new SAFPTPortugueseVatNumber();
		nif.setSAFPTPortugueseVatNumber(new BigInteger(Nif));
		return nif;
	}

	private static SAFPTtextTypeMandatoryMax100Car get100(String val) {
		SAFPTtextTypeMandatoryMax100Car value = new SAFPTtextTypeMandatoryMax100Car();
		value.setSAFPTtextTypeMandatoryMax100Car(val);
		return value;
	}

	private static SAFPTtextTypeMandatoryMax200Car get200(String val) {
		SAFPTtextTypeMandatoryMax200Car value = new SAFPTtextTypeMandatoryMax200Car();
		value.setSAFPTtextTypeMandatoryMax200Car(val);
		return value;
	}

	private static SAFPTtextTypeMandatoryMax60Car get60(String val) {
		SAFPTtextTypeMandatoryMax60Car value = new SAFPTtextTypeMandatoryMax60Car();
		value.setSAFPTtextTypeMandatoryMax60Car(val);
		return value;
	}

	private static SAFPTtextTypeMandatoryMax50Car get50(String val) {
		SAFPTtextTypeMandatoryMax50Car value = new SAFPTtextTypeMandatoryMax50Car();
		value.setSAFPTtextTypeMandatoryMax50Car(val);
		return value;
	}

	private static SAFPTtextTypeMandatoryMax20Car get20(String val) {
		SAFPTtextTypeMandatoryMax20Car value = new SAFPTtextTypeMandatoryMax20Car();
		value.setSAFPTtextTypeMandatoryMax20Car(val);
		return value;
	}

	private static SAFPTtextTypeMandatoryMax32Car get32(String val) {
		SAFPTtextTypeMandatoryMax32Car value = new SAFPTtextTypeMandatoryMax32Car();
		value.setSAFPTtextTypeMandatoryMax32Car(val);
		return value;
	}

	public static String writeADBBean(ADBBean aBean) throws XMLStreamException {
		if (null == aBean)
			return "null";
		OMElement omElement;
		try {
			// The preferred way of serializing objects generated by Axis2's
			// WSDL2JAVA involves methods that are named the same on every
			// class but that aren't inherited from any base class. So, use
			// reflection to find them.
			QName qname;
			try {
				Field qnameField = aBean.getClass().getField("MY_QNAME");
				qname = (QName) qnameField.get(aBean);
			} catch (Exception e) {
				// Some Axis2-generated objects don't have QNames. Supply
				// one based on the object's class.
				qname = new QName(aBean.getClass().getCanonicalName());
			}
			Method getOMElement = aBean.getClass().getMethod("getOMElement",
					QName.class, OMFactory.class);
			omElement = (OMElement) getOMElement.invoke(aBean, qname,
					OMAbstractFactory.getOMFactory());
		} catch (Exception e) {
			throw new XMLStreamException(
					"Cannot serialize " + aBean.toString(), e);
		} catch (NoClassDefFoundError e) {
			throw new XMLStreamException(
					"Cannot serialize " + aBean.toString(), e);
		}
		String serialized = omElement.toStringWithConsume();
		return serialized;
	}

	private static void getHeader() {

		// <wsse:Security
		// xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/
		// oasis-200401-wss-wssecurity-secext-1.0.xsd"
		// soapenv:mustUnderstand="1">
		//
		// <wsu:Timestamp
		// xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/
		// oasis-200401-wss-wssecurity-utility-1.0.xsd"
		// wsu:Id="Timestamp-6557466">
		//
		// <wsu:Created>2007-04-30T18:29:15.687Z</wsu:Created>
		// <wsu:Expires>2007-04-30T18:34:15.687Z</wsu:Expires>
		// </wsu:Timestamp>
		//
		// <wsse:UsernameToken
		// xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/
		// oasis-200401-wss-wssecurity-utility-1.0.xsd"
		// wsu:Id="UsernameToken-4055741">
		//
		// <wsse:Username>wsuser</wsse:Username>
		// <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/
		// oasis-200401-wss-username-token-profile-1.0#PasswordDigest">
		// YaVaSHBtqjGDWoHEdB1zuB3CR68=</wsse:Password>
		//
		// <wsse:Nonce>E62qDYhYVoUkJSukJGrvdA==</wsse:Nonce>
		// <wsu:Created>2007-04-30T18:29:15.665Z</wsu:Created>
		// </wsse:UsernameToken>
		// </wsse:Security>

	}
}
